/*----------------------------------------------------------------------------*/
/* Copyright 2020-2021 NXP                                                    */
/*                                                                            */
/* NXP Confidential. This software is owned or controlled by NXP and may only */
/* be used strictly in accordance with the applicable license terms.          */
/* By expressly accepting such terms or by downloading, installing,           */
/* activating and/or otherwise using the software, you are agreeing that you  */
/* have read, and that you agree to comply with and are bound by, such        */
/* license terms. If you do not agree to be bound by the applicable license   */
/* terms, then you may not retain, install, activate or otherwise use the     */
/* software.                                                                  */
/*----------------------------------------------------------------------------*/

/** \file
*
* Example Source for NfcrdlibEx10_MIFAREDESFire_EVx that demonstrates communication
* with MIFARE DESFire EV2 contactless IC and MIFARE DESFire EV3 contactless IC cards.
* This example will Detect and activater the Type-A card.
* If card is MIFAREDESFire EV2 and MIFAREDESFire EV3 then it will format the card and create application
* After creating application, it will create one Standard File. It will
* demo read and write operations with the card.
* KEYTYPE is AES.
* Please refer Readme.txt file for Hardware Pin Configuration, Software Configuration and steps to build and
* execute the project which is present in the same project directory.
*
* $Author$
* $Revision$ (v07.02.00)
* $Date$
*
*/

/**
* Reader Library Headers
*/
#include <phApp_Init.h>
#include "phpalCt/phpalCt.h"
#include "phalMfdfEVx.h"

#include "log2.h"
#include <Reader/Reader.h>
#include "BSP_Sleep.h"

#include "config/config.h"

/* *****************************************************************************************************************
* MACROS/Defines
* ***************************************************************************************************************** */
#define PH_EXMFCRYPTO_MFDFCRYPTO_MIFAREDESFIRE_SAK      0x20

#define AES128_KEY_ADDRESS       0       /* PICC Key entry number in key store. */
#define AES128_KEY_VERSION       0       /* PICC Key entry number in key store. */

#define PICC_MASTER_KEY          0
#define APP_MASTER_KEY           0

#define SAM_MASTER_KEY			 0
#define SAM_MASTER_KEY_VERSION	 0

#define KEYCOUNT				 1
#define KEYVERSIONS 			 1

#define PH_EX10_CARD_REMOVED_CHK_CNT  5

#define SAM_LC0         0x00U /**< SAM logical channel 0 */

#define PH_EXCT7816_MAX_ATR_SIZE         33
#define PH_EXCT7816_MAX_NO_APDU          6
#define PH_EXCT7816_APDU_LENGTH          13

#define DESFIRE_DEFAULT 			0x01
#define DESFIRE_DEFAULT_AES			0x02

#define APPLE_KEY_ID_DES			0x21
#define APPLE_KEY_ID_AES			0x22

#define GOOGLE_KEY_ID_AES			0x23

#define SAM_AV3_GET_VERSION_STATE					30
#define SAM_AV3_GET_VERSION_STATE_UNACTIVATED		0x03

/*******************************************************************************
**   Global Variable Declaration
*******************************************************************************/

phacDiscLoop_Sw_DataParams_t       * pDiscLoop;     /* Pointer to Discovery loop data-params */
phpalI14443p3a_Sw_DataParams_t     * ppalI14443p3a; /* Pointer to PAL 14443-3A data-params */
phpalI14443p4_Sw_DataParams_t      * ppalI14443p4;  /* Pointer to PAL 14443-4 data-params */
phKeyStore_Sw_DataParams_t  	   * pKeyStore;
//phalMfdfEVx_Sw_DataParams_t        * palMfdfEVx;    /* Pointer to MIFAREDESFire Ev2 data-params */
phpalMifare_Sw_DataParams_t			*ppalMifare;


phKeyStore_Sw_KeyEntry_t       keyEntry[KEYCOUNT];
phKeyStore_Sw_KeyVersionPair_t keyVersion[KEYCOUNT * KEYVERSIONS];
phKeyStore_Sw_KUCEntry_t       keyUsage[KEYCOUNT];

phhalHw_SamAV3_DataParams_t stHal_SamAv3;
phCryptoSym_Sw_DataParams_t stCryptoEnc;
phCryptoSym_Sw_DataParams_t stCryptoMAC;
phCryptoSym_Sw_DataParams_t stCryptoSymRnd;
phCryptoRng_Sw_DataParams_t stCryptoRng;
phalMfdfEVx_SamAV3_NonX_DataParams_t  palMfdfEVx;	/* Pointer to MIFAREDESFire EVx data-params for SAM in S mode */
phTMIUtils_t						pTMI;


uint8_t aTx_SamBuffer[260];
uint8_t aRx_SamBuffer[260];

uint8_t aTMIBuffer[280];//Buffer for DESFire TMI collection
uint8_t aCmdBuffer[280];//Buffer for DESFire commands

/* AES default key */
static uint8_t aAES128Key[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};



/*DESFire default Key entry*/
static uint8_t pDESFireDefault[] = {
		0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0xF5,0x32,0xF0,																					//DF_AID
		0x01,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x01, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};
		
/*apple_wallet Key entry*/
static uint8_t apple_wallet_key_des[] = {
		0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x00,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x00, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

static uint8_t apple_wallet_key_aes[] = {
		0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x01,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

/*===================================================================================*/
#pragma pack(1)
	typedef struct {
		uint8_t keys[3][16];
		uint8_t aid[3];
		uint8_t key_no;
		uint8_t kce_no,kce_ver;
		uint8_t kuc_no;
		uint16_t set;
		uint8_t key_ver[3];
		uint16_t ext_set;
		uint8_t kae_no,kae_ver;
	}sam_key_entry_t;

	typedef struct {
		uint8_t tag1;
		uint8_t length1;
		uint8_t tag2;
		uint8_t length2;
		uint8_t info;
		uint8_t pdcap[2];
		uint8_t vcuid[7];
		uint8_t version_id;
		uint8_t timestamp[5];
	}fci_info_t;

	typedef struct {
		uint8_t major;
		uint8_t minor;
		uint8_t customer_code[5];
		uint8_t credential_id[8];
		uint8_t reissue_code;
		uint8_t pin_code[4];
		uint8_t customer_data[20];
		uint8_t signature[8];
	}acd_ev1_t;

	typedef struct {
		uint16_t head;
		uint8_t data[8];
		uint8_t wg_num;
		uint8_t wg_format;
	}default_data_t;
	
	typedef struct {
		uint8_t wg_num;
		uint8_t wg_format;
		uint8_t data[18];
	}custom_data_t;
#pragma pack()
/*===================================================================================*/
/*DESFire default Key entry*/
static sam_key_entry_t google_wallet_key_entry = {
		.keys[0] = {0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0xF5,0x32,0xF0},																					//DF_AID
		.key_no = 0x01,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_des = {
		.keys[0] = {0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x1E,0xA1},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00000,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_aes = {
		.keys[0] = {0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x01,0x1E,0xA1},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

/*=============================================================================================*/

#define AID_MANU		0xCF0001
#define AID_USER		0xCF0002

#define KID_KFR0		0x01
#define KID_KFR			0x02
#define KID_KFM			0x03

#define KFR0_KEY_NO		0x01

static const uint8_t key_kfr0[16] = {0x5A,0x4B,0x52,0x65,0x61,0x64,0x65,0x72,0x4D,0x33,0x35,0x36,0x22,0x22,0x33,0x33};
static const uint8_t key_kfr[16] = {0x5A,0x4B,0x52,0x65,0x61,0x64,0x65,0x72,0x4D,0x33,0x35,0x36,0x22,0x22,0x33,0x33};
static const uint8_t key_kfm[16] = {0x5A,0x4B,0x52,0x65,0x61,0x64,0x65,0x72,0x4D,0x33,0x35,0x36,0x88,0x88,0x99,0x99};

typedef enum {
	KEY_T_3DES = 1,
	KEY_T_AES128 = 2,
	KEY_T_3K3DES = 3,
	KEY_T_AES192 = 4,
	KEY_T_AES256 = 5,
	KEY_T_MAX,
}key_type_t;

typedef enum {
	CARD_T_USER = 0,		//用户配置卡
	CARD_T_CUSTOM = 1,		//授权卡
	CARD_T_MANU = 2,		//厂商配置卡
	CARD_T_INIT = 3,		//激活卡
}card_type_t;

#pragma pack(1)

//公共文件
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t type;		//类型：0 - 用户配置卡。1 - 授权卡。2 - 厂商配置卡。3 - 激活卡。	
	uint8_t isser_code[16];//厂商信息
	uint8_t cmac[8];
}card_info_t;

typedef struct {
	uint8_t key_id;
	uint8_t key_ver;
	uint8_t key_type;
	uint8_t key_val[32];
}key_t;

//配置卡密钥
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t isser_code[16];//验证码
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}cfg_keys_t;
//密钥数据
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}key_data_t;

#pragma pack()

typedef struct {
	card_info_t info;
	cfg_keys_t cfg_keys;
	key_data_t key_datas;
	cfg_apple_wallet_t cfg_apple;
	cfg_google_wallet_t cfg_google;
}cfg_card_t;

int reader_cfg_gen_div(uint8_t *uid, uint8_t ulen, uint8_t* aid, uint8_t* div){
	uint8_t dlen = 0;
	memcpy(div, uid, ulen);
	dlen = ulen;
	memcpy(div + dlen, aid, 3);
	dlen += 3;
	return dlen;
}

int reader_cfg_select_aid(uint8_t aid[3]){
    phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	return phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, aid, NULL);	
}

int reader_cfg_auth(uint8_t key_id, uint8_t key_no, uint8_t* div, uint8_t dlen){
    phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	//认证KFR0
    /*AES Authenticate First*/
    status = phalMfdfEVx_Authenticate(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			key_id,
            0x00,
			key_no,
			div,
			dlen);
	return status;
}

int reader_cfg_read(uint8_t fid, uint8_t offset, uint8_t len, void* buf){
    phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	uint8_t bFileNo = fid;
	uint8_t Len[] = {len,0x00,0x00}; //LSB first!
	uint8_t Offset[] = {offset,0x00,0x00};//LSB first!
	uint8_t * pRxData = NULL;
	uint16_t RxLen = 0;
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if(status){
		return status;
	}
	if(len != RxLen){
		LOG2_ERR("len = %d, RxLen = %d", len, RxLen);
		return -1;
	}
	memcpy(buf, pRxData, len);
	return status;
}
/*=======================================================================================================================*/
//读取卡信息文件
int reader_cfg_read_comm(uint8_t* uid, uint8_t ulen, card_info_t* info){
	int ret;
	uint8_t aid[3] = {0x01,0x00,0xCF};
	ret = reader_cfg_select_aid(aid);
	if(ret){
		return ret;
	}
	uint8_t div[16];
	uint8_t dlen = reader_cfg_gen_div(uid, ulen, aid, div);
	ret = reader_cfg_auth(KID_KFR0, KFR0_KEY_NO, div, dlen);
	if(ret){
		LOG2_ERR("auth KID_KFR0 fail!");
		return ret;
	}	
	uint8_t fid = 0x00;
	ret = reader_cfg_read(fid, 0, sizeof(*info), info);
	if(ret){
		LOG2_ERR("read fail: %d", ret);
		return ret;
	}
	//TODO: CMAC校验
	return ret;
}
//读取配置密钥文件
int reader_cfg_read_custom(uint8_t* uid, uint8_t ulen, card_info_t* info){
	int ret;
	uint8_t aid[3] = {0x01,0x00,0xCF};
	ret = reader_cfg_select_aid(aid);
	if(ret){
		return ret;
	}
	uint8_t div[16];
	uint8_t dlen = reader_cfg_gen_div(uid, ulen, aid, div);
	ret = reader_cfg_auth(KID_KFR0, KFR0_KEY_NO, div, dlen);
	if(ret){
		LOG2_ERR("auth KID_KFR0 fail!");
		return ret;
	}	
	uint8_t fid = 0x00;
	ret = reader_cfg_read(fid, 0, sizeof(*info), info);
	if(ret){
		LOG2_ERR("read fail: %d", ret);
		return ret;
	}
	//TODO: CMAC校验
	return ret;
}
/*=========================================================================================*/
//初始化配置卡
int reader_cfg_init(cfg_card_t* card){
	//检查配置卡校验码
	//1.擦除用户配置
	// cfg_clear(CFG_ID_USER);
	//2.擦除用户密钥
	return -1;	
}
//客户化卡
int reader_cfg_custom(cfg_card_t* card){
	//1.校验验证码
	//2.导入配置卡密钥
	return -1;
}

//配置卡
int reader_cfg_param(cfg_card_t* card){
	//1.校验验证码
	//2.导入配置卡密钥
	return -1;
}

/*=========================================================================================*/

int reader_wavelynx_config(uint8_t* uid, uint8_t ulen){
	card_info_t card_info;
	int ret = reader_cfg_read_comm(uid, ulen, &card_info);
	if(ret){
		return ret;
	}
	switch(card_info.type){
	case CARD_T_INIT:{
	}
	break;
	default:
		LOG2_ERR("Unkown card type: %d", card_info.type);
		ret = -1;
		break;
	}
	return ret;
}
/*=======================================================================================================================*/

static uint16_t sam_key_entry_get_key_set(uint8_t key_type){
	switch(key_type){
	case KEY_T_3DES: return 0;
	case KEY_T_AES128: return 0x24;
	default: return 0;
	}
}

static phStatus_t reader_sam_load_key(uint8_t key_id, uint8_t key_no, uint8_t key_type, uint8_t key_ver, const uint8_t* key_val, const uint8_t* aid){
    phStatus_t  status = 0;
	sam_key_entry_t key_entry = {
//			.keys[0] = {0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
//			.aid = {0x01,0x1E,0xA1},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
//			.set = 0x00024,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	};

	key_entry.key_no = key_no;
	key_entry.set = sam_key_entry_get_key_set(key_type);
	memcpy(&key_entry.keys[0][0], key_val, 16);
	if(aid){
		memcpy(key_entry.aid, aid, 3);
	}
	key_entry.key_ver[0] = key_ver;
	
	uint8_t * pKeyData = (uint8_t*)&key_entry;
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, key_id, 0xFF, pKeyData, sizeof(key_entry));
	if(status != PH_ERR_SUCCESS) {
		LOG2_ERR(" failed: %04X", status);
		return status;
	}
	return status;
}

#pragma pack(1)
typedef struct {
	uint8_t ver_a;
	uint8_t ver_b;
	uint8_t ver_c;
	uint8_t df_aid[3];
	uint8_t df_key_no;
	uint8_t key_no_cek;
	uint8_t ref_no_kuc;
	uint16_t set;
	uint16_t ext_set;
	uint8_t key_no_aek;
	uint8_t key_vaek;
}sam_key_entry_info_t;
#pragma pack()

static phStatus_t reader_sam_get_key(uint8_t key_id, sam_key_entry_info_t* key_entry){
	uint8_t	 aKeyEntryBuffer[PHHAL_HW_SAMAV3_KEYENTRY_SIZE];
	uint8_t	 bKeyEntryLen = 0;
    phStatus_t  status = 
			phhalHw_SamAV3_Cmd_SAM_GetKeyEntry(
				   &stHal_SamAv3,
				   key_id,
				   0x00,
				   aKeyEntryBuffer,
				   &bKeyEntryLen
			   );
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR(" failed: %04X", status);
		return status;
	}
	
	* key_entry = *(sam_key_entry_info_t*)aKeyEntryBuffer;
	LOG2_INF("key_entry->ver_a: %02X", key_entry->ver_a);
	return status;
}

static phStatus_t reader_sam_check_key(uint8_t key_id, uint8_t key_ver){
	sam_key_entry_info_t key_entry;
	phStatus_t status = reader_sam_get_key(key_id, &key_entry);
	if(status){
		return status;
	}
	if(key_entry.ver_a != key_ver){
		return 1;
	}
	return status;
}

static int reader_w_load_default_key(uint8_t key_id, uint8_t key_ver, const uint8_t* key_val){
	if(reader_sam_check_key(key_id, key_ver)){
		return reader_sam_load_key(key_id, 0, KEY_T_AES128, key_ver, key_val, NULL);
	}
	return 0;
}

static int reader_wavelynx_setup(void){
	//1.检查密钥，若默认密钥不存在，则装载默认密钥
	if(reader_w_load_default_key(KID_KFR0, 1, key_kfr0)){
		LOG2_WRN("load KFR0 fail!");
		return -1;
	}
	if(reader_w_load_default_key(KID_KFR, 1, key_kfr)){
		LOG2_WRN("load KID_KFR fail!");
		return -1;
	}
	if(reader_w_load_default_key(KID_KFM, 1, key_kfm)){
		LOG2_WRN("load KID_KFM fail!");
		return -1;
	}
	return 0;
}

/*=======================================================================================================================*/

phStatus_t StoreKeysInKeyStore(phKeyStore_Sw_DataParams_t * pKeyStore)
{
    phStatus_t status;

    status = phKeyStore_FormatKeyEntry(pKeyStore, AES128_KEY_ADDRESS, PH_CRYPTOSYM_KEY_TYPE_AES128);
    CHECK_SUCCESS(status);

    return phKeyStore_SetKeyAtPos(pKeyStore, AES128_KEY_ADDRESS, 0x00, PH_CRYPTOSYM_KEY_TYPE_AES128,
            aAES128Key, AES128_KEY_VERSION);
}

void reader_wavelynx_init(void){
	phStatus_t			  status = PH_ERR_INTERNAL_ERROR;
	phNfcLib_Status_t	  dwStatus;
	/* Print Example application name */
	DEBUG_PRINTF("\n *** MIFARE DESFire EV2 Example *** \n");
	
	/* Initialize library */
	
	/* Set the generic pointer */
	pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
	pDiscLoop = (phacDiscLoop_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_AC_DISCLOOP);
	ppalI14443p3a = (phpalI14443p3a_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3A);
	ppalI14443p4 = (phpalI14443p4_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);
	pKeyStore = (phKeyStore_Sw_DataParams_t *)	phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	//palMfdfEVx = (phalMfdfEVx_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_AL_MFDFEVX);//Not needded
	ppalMifare= (phpalMifare_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_MIFARE);
	
	phTMIUtils_Init(&pTMI,aTMIBuffer,sizeof(aTMIBuffer));
	
	//INIT DESFire Params
	  status = phalMfdfEVx_SamAV3_NonX_Init(
				&palMfdfEVx,
				sizeof(palMfdfEVx),
				&stHal_SamAv3,
				ppalMifare,
				&pTMI,
				aCmdBuffer,
				sizeof(aCmdBuffer)
			 );
	
	  if(status != PH_ERR_SUCCESS) {
			DEBUG_PRINTF("\n DESFire Init failed!");
			 DEBUG_ERROR_PRINT(status);
		 }
	
	phpalCt_Init();
    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t pDataParams ;


    /* Configure Discovery Loop functionality required by this example to only activate Type A cards. */
//	    ConfigureDiscoveryLoop();

    /** Check the card presence */
    DEBUG_PRINTF("Waiting for CT card insertion.\n");

	DEBUG_PRINTF("CT card detected\n");

    /* The response buffer is used to optimize the code */
	pDataParams.pbAtrBuffer = (uint8_t *)(&aRx_SamBuffer);
	pDataParams.bSizeOfATRbuffer = PH_EXCT7816_MAX_ATR_SIZE;

	/* Activate the card */
	status = phpalCt_ActivateCard(&pDataParams);
	if(PH_ERR_SUCCESS != status)
	{
		DEBUG_PRINTF("Card Activation failed.\n");
		DEBUG_ERROR_PRINT(status);
	}


	/** Initialize Crypto components. */
	CHECK_SUCCESS_VOID(phCryptoSym_Sw_Init(&stCryptoEnc, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore));
	CHECK_SUCCESS_VOID(phCryptoSym_Sw_Init(&stCryptoMAC, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore));
	CHECK_SUCCESS_VOID(phCryptoSym_Sw_Init(&stCryptoSymRnd, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore));
	CHECK_SUCCESS_VOID(phCryptoRng_Sw_Init(&stCryptoRng, sizeof(phCryptoRng_Sw_DataParams_t), &stCryptoSymRnd));

	DEBUG_PRINTF("Card Activation Successful.\n");
	LOG2_BUF_INF("ATR:\n",pDataParams.pbAtrBuffer, pDataParams.bAtrReceivedLength);

    /* init. keystore */
    status = phKeyStore_Sw_Init(pKeyStore,
        sizeof(phKeyStore_Sw_DataParams_t),
        keyEntry,
        KEYCOUNT,
        keyVersion,
        KEYVERSIONS,
        keyUsage,
        KEYCOUNT);
    if(status != PH_ERR_SUCCESS) {
    	 DEBUG_PRINTF("\n Keystore Init failed!");
    	 DEBUG_ERROR_PRINT(status);
    }

    /* Set all the keys in the S/W key store */
    status = StoreKeysInKeyStore(pKeyStore);
    if(status != PH_ERR_SUCCESS) {
    	 DEBUG_PRINTF("\n store keys in keystore failed!");
    	 DEBUG_ERROR_PRINT(status);
    }
    /*Init RNG seed (take all 00s AES key Array)<- not production grade*/
    status = phCryptoRng_Seed(&stCryptoRng,&aAES128Key[0],0x10);
    if(status != PH_ERR_SUCCESS) {
       	 DEBUG_PRINTF("\n Rng Seed init failed!");
       	 DEBUG_ERROR_PRINT(status);
       }

	 /* Init SAM AV3 */
	 status = phhalHw_SamAV3_Init(
		&stHal_SamAv3,
		sizeof ( stHal_SamAv3 ),
		&pDataParams, //?phpalCt_DataParams_t pDataParams <-- isnt this a pal, not bal?
		pHal,
		pKeyStore,
		&stCryptoEnc,
		&stCryptoMAC,
		&stCryptoRng,
		NULL,
		NULL,
		PHHAL_HW_SAMAV3_OPMODE_NON_X,
		0x00,
		aTx_SamBuffer,
		sizeof ( aTx_SamBuffer ),
		aRx_SamBuffer,
		sizeof ( aRx_SamBuffer ),
		NULL
		);


	 if(status == PH_ERR_SUCCESS) {
		 DEBUG_PRINTF("\n SAM Init successful!");
	 }
	 else {
		DEBUG_PRINTF("\n SAM Init failed!");
		DEBUG_ERROR_PRINT(status);
	}

    /* SAM Get Version */
    uint8_t rxLen = 0;
    status = phhalHw_SamAV3_Cmd_SAM_GetVersion(
    		&stHal_SamAv3,
			aRx_SamBuffer,
			&rxLen);

    if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF("\n SAM GetVersion failed!");
		DEBUG_ERROR_PRINT(status);
    }
    else{
    	 /* Print SAM Version */
    	DEBUG_PRINTF("\nSAM AV3 Get Version: ");
    	LOG2_BUF_INF("\t", aRx_SamBuffer, rxLen);
    }

	if(aRx_SamBuffer[SAM_AV3_GET_VERSION_STATE] == SAM_AV3_GET_VERSION_STATE_UNACTIVATED) {
		/* Activate SAM AV3 if not yet done */
		status = phhalHw_SamAV3_Cmd_SAM_LockUnlock(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_LOCK_UNLOCK_TYPE_ACTIVATE_SAM,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION,
				0,
				0,
				0
		);

	}

	/* Perform HostAuth with SAM Master Key. */
	DEBUG_PRINTF("\nSAM Host Authentication: ");
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
			&stHal_SamAv3,
			PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_PLAIN,
			AES128_KEY_ADDRESS,
			AES128_KEY_VERSION,
			SAM_MASTER_KEY,
			SAM_MASTER_KEY_VERSION
	);
	if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		DEBUG_PRINTF(" successful!");
	}
}

int reader_wavelynx_load_keys(void){
    phStatus_t  status = 0;
	
//		reader_wavelynx_setup();
	
	/* Change Key Entry to type AES */
	LOG2_PRINT("\n Google AES key loading: ");
	pDESFireDefault[55] = 0x24; //reuse of same array, just change setting to AES key (see datasheet)
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, GOOGLE_KEY_ID_AES, 0xFF, &pDESFireDefault[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}

	LOG2_PRINT("\nApple DES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_DES, 0xFF, &apple_wallet_key_des[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	LOG2_PRINT("\nApple AES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_AES, 0xFF, &apple_wallet_key_aes[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	return status;
}


#if 0
int reader_wavelynx_load_keys(void){
    phStatus_t  status = 0;
	/* Change Key Entry to type AES */
	LOG2_PRINT("\n Google AES key loading: ");
	pDESFireDefault[55] = 0x24; //reuse of same array, just change setting to AES key (see datasheet)
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, GOOGLE_KEY_ID_AES, 0xFF, &pDESFireDefault[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	LOG2_PRINT("\nApple DES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_DES, 0xFF, &apple_wallet_key_des[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	LOG2_PRINT("\nApple AES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_AES, 0xFF, &apple_wallet_key_aes[0], 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	return status;
}
#endif 

/***********************************************************************************************
* \brief   This function demonstrates the MIFARE DESFire EV3 application as mentioned below
*
* \param   *pParams
* \return  This function will never return
**********************************************************************************************/
static void reader_print_fci(const fci_info_t* fci){
	LOG2_PRINT("\n===========FCI============\n");
	LOG2_PRINT("info: %02X\n", fci->info);
	LOG2_PRINT("pdcap: %02X%02X\n", fci->pdcap[0], fci->pdcap[1]);
	LOG2_PRINT("vcuid: %02X%02X%02X%02X%02X%02X%02X\n", fci->vcuid[0], fci->vcuid[1], 
		fci->vcuid[2], fci->vcuid[3], fci->vcuid[4], fci->vcuid[5], fci->vcuid[6]);
	LOG2_PRINT("version_id: %02X\n", fci->version_id);
	LOG2_PRINT("timestamp: %02X%02X%02X%02X%02X\n", fci->timestamp[0], fci->timestamp[1], 
		fci->timestamp[2], fci->timestamp[3], fci->timestamp[4]);
	LOG2_PRINT("===========================\n");
}

static uint8_t reader_mf2go_gen_div(const fci_info_t* fci, const uint8_t aid[3], uint8_t *div){
	uint8_t len = 0;
//		div[len++] = 0x01;
	memcpy(&div[len], fci->vcuid, sizeof(fci->vcuid));
	len += sizeof(fci->vcuid);
	memcpy(&div[len], aid, 3);
	len += 3;
	div[len++] = fci->info;
	memcpy(&div[len], fci->timestamp, sizeof(fci->timestamp));
	len += sizeof(fci->timestamp);
	return len;
}

int reader_wavelynx_read_google_wallet(credential_t* cred)
{
    phStatus_t status;
    uint32_t iChoice = 1;

    uint8_t versionInfo[28];
    uint8_t AID[] = {0xF5,0x32,0xF0};
    uint8_t ISOFileID[] = {0xA5,0xA5};
    uint8_t ISODFName[] = {0xa0, 0x00, 0x00, 0x03, 0x96, 0x56, 0x43, 0x41, 0x03, 0xf5, 0x32, 0xf0, 0x00, 0x02, 0x09, 0x01};
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    /* Clear the console. */
	LOG2_RESET_LEVEL();
    LOG2_DBG("A Ticket is discovered \n");

	
    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
//	    status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, 0x00, &AID[0], NULL);
fci_info_t fci_info = {0};
{
	uint8_t *pFCI = NULL;
	uint16_t wFCILen = 0;
    status = phalMfdfEVx_IsoSelectFile(pAlMfdfEVx, 
    	PHAL_MFDFEVX_FCI_RETURNED, 
    	PHAL_MFDFEVX_SELECTOR_4,
    	NULL,
    	ISODFName, sizeof(ISODFName),
    	0,
    	&pFCI, &wFCILen
    	);
	CHECK_SUCCESS(status);
	LOG2_BUF_DBG("FCI", pFCI, wFCILen);
	uint8_t len = wFCILen < sizeof(fci_info) ? wFCILen : sizeof(fci_info);
	memcpy(&fci_info, pFCI, len);
	reader_print_fci(&fci_info);
}

	uint8_t div[32] = {0};
	uint8_t dlen = reader_mf2go_gen_div(&fci_info, AID, div);
	
	LOG2_BUF_DBG("div", div, dlen);
	uint8_t key_no = 1;
	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			GOOGLE_KEY_ID_AES,
            0x00,
			key_no,
			div,
			dlen);
     CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 2;
	uint8_t Len[] = {sizeof(acd_ev1_t),0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[64] = {0};
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	LOG2_PRINT("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if(status == PH_ERR_SUCCESS){
			memcpy(RxData+rlen, pRxData, RxLen);
			rlen += RxLen;
		}
	}
	CHECK_SUCCESS(status);
	if(status == PH_ERR_SUCCESS){
		LOG2_BUF_INF("\t", RxData, rlen);
		// acd_ev1_t* acd = (acd_ev1_t*)RxData;
		// reader_get_access_data(acd->customer_data, cred);
		// LOG2_DBG("wg: %d", cred->nbit);
		// LOG2_BUF_DBG("data", cred->credential, cred->clen);
	}
	else{
		return status;
	}	
	//		6. A WRITE command is performed on the Reissue Code field.
{
	uint8_t data[1] = { 0 };
	uint16_t dlen = 0;
	uint8_t offset[3] = {0x0F, 0x00, 0x00};
	uint8_t length[3] = {1, 0x00, 0x00};
	bFileNo = 2;
	LOG2_DBG("write data");
	// ret = Reader_MFDF_WriteData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, bFileNo, offset, data, length);
	status = phalMfdfEVx_WriteData(pAlMfdfEVx, 
		PHAL_MFDFEVX_COMMUNICATION_ENC, 
		PHAL_MFDFEVX_APPLICATION_CHAINING, 
		bFileNo, 
		offset, 
		data, 
		length
		);
	if((status != PH_ERR_SUCCESS) && ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING)){
		LOG2_ERR("phalMfdfEVx_WriteData fail: %04X", status);
		return status;
	}
}
{
	uint8_t end_apdu[] = {0x90, 0xC7, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_DBG("COMMIT TRANSACTION");
//		void* pal14443a  = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4A);
	status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
	if(status){
		LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
	}
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);
}
    return PH_ERR_SUCCESS;
}


int reader_wavelynx_read_apple_wallet(credential_t* cred)
{
    phStatus_t status;
	uint8_t uid[8] = {0};
	uint8_t ulen;
    uint8_t AID[] = {0x00,0x1E,0xA1};
    uint8_t AID2[] = {0x01,0x1E,0xA1};
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    /* Clear the console. */
	LOG2_RESET_LEVEL();
    LOG2_DBG("A Ticket is discovered \n");
	
    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
//2. SELECT the Privacy application and authenticate using the undiversified key.
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID, NULL);
	if(status){
		LOG2_ERR("select app1 fail: %04X", status);
		return status;
	}

	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
	uint8_t key_no = 0;
    /*AES Authenticate First*/
    status = phalMfdfEVx_Authenticate(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_NO_DIVERSIFICATION,
			APPLE_KEY_ID_DES,
            0x00,
			key_no,
			NULL,
			0);
     CHECK_SUCCESS(status);

	status = phalMfdfEVx_GetCardUID(pAlMfdfEVx, 
		PHAL_MFDFEVX_GET_CARD_UID_EXCHANGE_OPTION_OFF,
		PHAL_MFDFEVX_GET_CARD_UID_OPTION_NUID_NOT_RETURNED,
		uid);
	CHECK_SUCCESS(status);
	ulen = 7;
	LOG2_BUF_DBG("uid:", uid, 7);
	LOG2_PRINT("\nphalMfdfEVx_SelectApplication 2: \n");
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID2, NULL);
	CHECK_SUCCESS(status);
	
	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			APPLE_KEY_ID_AES,
            0x00,
			key_no,
			uid,
			ulen);
     CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 1;
	uint8_t Len[] = {16,0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[64] = {0};
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	LOG2_PRINT("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if(status == PH_ERR_SUCCESS){
			memcpy(RxData+rlen, pRxData, RxLen);
			rlen += RxLen;
		}
	}
	CHECK_SUCCESS(status);
	LOG2_BUF_INF("\t", RxData, rlen);
	//		6. A WRITE command is performed on the Reissue Code field.

{
	uint8_t end_apdu[] = {0x90, 0xEE, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_DBG("COMMIT TRANSACTION");
	status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
	if(status){
		LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
	}
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);
}
    return PH_ERR_SUCCESS;
}

int reader_read_wavelynx_tag(Reader_T* read, credential_t* cred){
	int ret;
	ret = reader_wavelynx_read_apple_wallet(cred);
	if(ret){
		ret = reader_wavelynx_read_google_wallet(cred);
	}
	return ret;
}
/***********************************************************************************************
*                            End Of File
**********************************************************************************************/
